#ifndef LIGHT_ENTITY_H
#define LIGHT_ENTITY_H

const float LIGHT_PROJECTOR_MAX_FOV = 175.f;

struct CLightEntity : public ILightSource, public Cry3DEngineBase
{
	static void StaticReset();

public:
	virtual EERType GetRenderNodeType() { return eERType_Light; }
	virtual const char * GetEntityClassName(void) const { return "LightEntityClass"; }
	virtual const char *GetName(void) const;
	virtual Vec3 GetPos(bool) const;
	virtual void Render(const SRendParams &);
	virtual IPhysicalEntity *GetPhysics(void) const { return 0; }
	virtual void SetPhysics(IPhysicalEntity *) { }
	virtual void SetMaterial(IMaterial * pMat) { m_pMaterial = pMat; }
	virtual IMaterial *GetMaterial(Vec3 * pHitPos = NULL) { return m_pMaterial; }
	virtual IMaterial *GetMaterialOverride() { return m_pMaterial; }
	virtual float GetMaxViewDist();
	VIRTUAL void SetLightProperties(const CDLight & light);
	VIRTUAL CDLight& GetLightProperties() { return m_light; };
	virtual void Release(bool);
	virtual void SetMatrix( const Matrix34& mat );
	VIRTUAL const Matrix34& GetMatrix( ) { return m_Matrix; }
	VIRTUAL struct ShadowMapFrustum * GetShadowFrustum(int nId = 0);
	virtual void GetMemoryUsage(ICrySizer * pSizer) const;
  virtual const AABB GetBBox() const { return m_WSBBox; }
  virtual void SetBBox( const AABB& WSBBox ) { m_WSBBox = WSBBox; }
  virtual void OffsetPosition(const Vec3& delta);
  VIRTUAL void SetCastingException(IRenderNode * pNotCaster) { m_pNotCaster = pNotCaster; }
  VIRTUAL bool IsLightAreasVisible();

	virtual struct IStatObj * GetEntityStatObj( unsigned int nPartId = 0, unsigned int nSubPartId = 0, Matrix34A * pMatrix = NULL, bool bReturnOnlyVisible = false); 
  virtual int GetSlotCount() const;
	virtual void SetViewDistRatio(int nViewDistRatio);

	void InitEntityShadowMapInfoStructure();
	void UpdateGSMLightSourceShadowFrustum(int nEngineFrameID);
	bool ProcessFrustum(int nLod, float fCamBoxSize, float fDistanceFromView, PodArray<struct SPlaneObject> & lstCastersHull, int nEngineFrameID);
  void InitShadowFrustum_SUN_Conserv(ShadowMapFrustum * pFr, int dwAllowedTypes, float fGSMBoxSize, float fDistance, int nLod, int nEngineFrameID);
	void InitShadowFrustum_SUN(ShadowMapFrustum * pFr, int dwAllowedTypes, float fCamBoxSize, int nLod, int nEngineFrameID);
	void InitShadowFrustum_PROJECTOR(ShadowMapFrustum * pFr, int dwAllowedTypes);
	void InitShadowFrustum_OMNI(ShadowMapFrustum * pFr, int dwAllowedTypes);
	void FillFrustumCastersList_SUN(ShadowMapFrustum * pFr, int dwAllowedTypes, PodArray<struct SPlaneObject> & lstCastersHull, int nEngineFrameID);
	void FillFrustumCastersList_PROJECTOR(ShadowMapFrustum * pFr, int dwAllowedTypes, int nEngineFrameID);
	void FillFrustumCastersList_OMNI(ShadowMapFrustum * pFr, int dwAllowedTypes, int nEngineFrameID);
	void CheckValidFrustums_OMNI(ShadowMapFrustum * pFr);
	bool CheckFrustumsIntersect(CLightEntity* lightEnt);
  bool GetGsmFrustumBounds(const CCamera& viewFrustum, ShadowMapFrustum* pShadowFrustum);
	void DetectCastersListChanges(ShadowMapFrustum * pFr);
	void OnCasterDeleted(IShadowCaster * pCaster);
	int MakeShadowCastersHull(PodArray<SPlaneObject> & lstCastersHull);
  static Vec3 GSM_GetNextScreenEdge(float fPrevRadius, float fPrevDistanceFromView);
  static float GSM_GetLODProjectionCenter(const Vec3& vEdgeScreen, float fRadius);
  static bool FrustumIntersection(const CCamera& viewFrustum, const CCamera& shadowFrustum);
  void UpdateCastShadowFlag(float fDistance);

	CLightEntity();
	~CLightEntity();

	CDLight m_light;
  bool m_bShadowCaster : 1;

	_smart_ptr<IMaterial> m_pMaterial;
	Matrix34 m_Matrix;
  IRenderNode * m_pNotCaster;

	// used for shadow maps
	struct ShadowMapInfo
	{
		ShadowMapInfo() { memset(this,0,sizeof(ShadowMapInfo)); }
		void Release(struct IRenderer * pRenderer);
		void GetMemoryUsage(ICrySizer * pSizer) const 
		{
#if !defined(__SPU__)
			pSizer->AddObject(this, sizeof(*this));		
#endif
		}
		struct ShadowMapFrustum * pGSM[MAX_GSM_LODS_NUM];
	} * m_pShadowMapInfo;

#ifdef USE_OCCLUSION_PROXY
  void DebugCoverageMask();
	void CheckUpdateCoverageMask(int nEngineFrameID);
	bool IsBoxAffected(const AABB & box);
	class CCullBuffer * m_arrCB[6];
	class CCamera* m_covCameras[6];
	bool m_bCoverageBufferDirty;
#endif

  AABB m_WSBBox;

private:
	static PodArray<SPlaneObject> s_lstTmpCastersHull;

	private:
		IStatObj * m_pStatObj;
};
#endif
